#pragma once

#include <assert.h>

#include <memory>

#include "record/bitmap.h"
#include "common/context.h"
#include "multi_version_defs.h"
/*
    MultiVersion PageHandle
    MultiVersion FileHanle
*/

class MultiVersionManager;

/* 对表数据文件中的页面进行封装 */
struct MultiVersionPageHandle {
    const MultiVersionFileHdr *file_hdr;  // 当前页面所在文件的文件头指针
    Page *page;                 // 页面的实际数据，包括页面存储的数据、元信息等
    MultiVersionPageHdr *page_hdr;        // page->data的第一部分，存储页面元信息，指针指向首地址，长度为sizeof(MultiVersionPageHdr)
    char *bitmap;               // page->data的第二部分，存储页面的bitmap，指针指向首地址，长度为file_hdr->bitmap_size
    char *slots;                // page->data的第三部分，存储表的记录，指针指向首地址，每个slot的长度为file_hdr->record_size

    MultiVersionPageHandle(const MultiVersionFileHdr *fhdr_, Page *page_) : file_hdr(fhdr_), page(page_) {
        page_hdr = reinterpret_cast<MultiVersionPageHdr *>(page->get_data() + page->OFFSET_PAGE_HDR);
        bitmap = page->get_data() + sizeof(MultiVersionPageHdr) + page->OFFSET_PAGE_HDR;
        slots = bitmap + file_hdr->bitmap_size;
    }

    // 返回指定slot_no的slot存储收地址
    char* get_slot(int slot_no) const {
        return slots + slot_no * file_hdr->record_size;  // slots的首地址 + slot个数 * 每个slot的大小(每个record的大小)
    }
};

/* 每个MultiVersionFileHandle对应一个表的数据文件，里面有多个page，每个page的数据封装在MultiVersionPageHandle中 */
class MultiVersionFileHandle {       
    friend class MultiVersionManager;

   private:
    DiskManager *disk_manager_;
    BufferPoolManager *buffer_pool_manager_;
    int fd_;        // 打开文件后产生的文件句柄
    MultiVersionFileHdr file_hdr_;    // 文件头，维护当前表文件的元数据

   public:
    MultiVersionFileHandle(DiskManager *disk_manager, BufferPoolManager *buffer_pool_manager, int fd)
        : disk_manager_(disk_manager), buffer_pool_manager_(buffer_pool_manager), fd_(fd) {
        // 注意：这里从磁盘中读出文件描述符为fd的文件的file_hdr，读到内存中
        // 这里实际就是初始化file_hdr，只不过是从磁盘中读出进行初始化
        // init file_hdr_
        disk_manager_->read_page(fd, MULTI_FILE_HDR_PAGE, (char *)&file_hdr_, sizeof(file_hdr_));
        // disk_manager管理的fd对应的文件中，设置从file_hdr_.num_pages开始分配page_no
        disk_manager_->set_fd2pageno(fd, file_hdr_.num_pages);
    }

    DISALLOW_COPY(MultiVersionFileHandle);

    MultiVersionFileHdr get_file_hdr() { return file_hdr_; }
    int GetFd() { return fd_; }

    /* 判断指定位置上是否已经存在一条记录，通过Bitmap来判断 */
    bool is_record(const Rid &rid) const {
        MultiVersionPageHandle page_handle = fetch_page_handle(rid.page_no);
        return Bitmap::is_set(page_handle.bitmap, rid.slot_no);  // page的slot_no位置上是否有record
    }

    std::unique_ptr<MultiVersionRecord> get_record(const Rid &rid, Context *context) const;

    Rid insert_record(char *buf, Context *context);
    void delete_record(const Rid &rid, Context *context);

    // void insert_record(const Rid &rid, char *buf);
    // void update_record(const Rid &rid, char *buf, Context *context);

    MultiVersionPageHandle create_new_page_handle();

    MultiVersionPageHandle fetch_page_handle(int page_no) const;

   private:
    MultiVersionPageHandle create_page_handle();

    void release_page_handle(MultiVersionPageHandle &page_handle);
};